Skip to content

feat(rules): lower conventional Cursor rules with honest capability rows (#100 stage 2) - #207

Merged
ScriptedAlchemy merged 2 commits into
mainfrom
wave5/100-s2-rules
Sep 1, 2026
Merged

feat(rules): lower conventional Cursor rules with honest capability rows (#100 stage 2)#207
ScriptedAlchemy merged 2 commits into
mainfrom
wave5/100-s2-rules

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

#100 stage 2, G5 priority slice ("Cursor rules first"). Adds the rule component surface end to end:

  • Authoring: conventional flat rules/*.mdc at the project root (mirrors skills/; project ignore rules apply; no new config key — the newcomer ledger stays intact).
  • Parsing/validation: closed frontmatter schema — exactly description, globs, alwaysApply, plus a peeled targets restriction that is never emitted. Fresh diagnostics AB4900–AB4906 (unreadable file, malformed YAML, unknown field, bad shape, unknown target, explicitly-targeted unsupported host, duplicate name). Explicitly targeting a host whose rules capability is not supported fails before artifact publication; defaulted targets simply omit on unsupported hosts.
  • Lowering: cursor emits rules/<name>.mdc byte-faithfully plus a rules: './rules/' manifest pointer; the multi-host plugin bundle's Cursor half does the same and AGENTS.md documents the Cursor-only boundary (LSP precedent).
  • Capability rows with evidence: cursor supported (pinned cursor/plugins@0701892 plugin.schema.json rules component pointer + dated provenance line, capabilitySha256 re-pinned); claude/codex/portable honestly unavailable with real reasons (no rules surface — no faked equivalent); composite plugin row is the Claude∧Codex intersection.
  • Boundaries: artifact validator admits the rules/ layout (.mdc only) for Cursor-shaped targets only; rules joins reserved payload destinations; output-ownership collision detection covers rule artifacts; rule-free projects emit no new entries and no pointer.

Test plan

  • rule-config.test.ts: closed schema, peeled targets, malformed YAML, deterministic discovery, unknown/unavailable/duplicate diagnostics, byte fidelity
  • cursor-adapter.test.ts / plugin-bundle.test.ts: emission, pointers, AGENTS.md note, rule-free packaging boundary
  • adapter-capability-states.test.ts / adapter-metadata.test.ts: rows + re-pinned sha
  • Full unit lane: 2136 tests, only the two pre-existing environmental failures also present on pristine origin/main (packed scaffold e2e + Flight dist load)
  • pnpm typecheck, pnpm lint green

Part of #100 (stage 2, Cursor rules first per G5). Refs #189.

@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a516fa8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T21:13:01.418257Z 9016926 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9016926231

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

): TargetArtifactWrite[] => (model.rules ?? [])
.filter((rule) => isSelected(rule.targets))
.map((rule) => ({
content: rule.markdown,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Strip bundle-only targets from emitted rules

When a rule declares targets in its frontmatter, parsing correctly removes that field from rule.frontmatter, but this writer emits the original rule.markdown, which still contains targets. Consequently the compiler publishes its internal target-selection extension as Cursor rule frontmatter instead of the documented closed Cursor schema; generate the emitted document from the peeled frontmatter and body, or otherwise remove only the targets field before writing.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a516fa8. parseRule now computes an emittedMarkdown alongside the authored bytes: when the authored frontmatter has no targets key the emitted document stays byte-identical (covered by a CRLF/no-trailing-newline regression); when targets was authored, the frontmatter is rebuilt from the validated portable fields using the same stringifyYaml convention as the Skill IR lowering, and a targets-only frontmatter collapses to a body-only document. ruleWriteEntries emits emittedMarkdown; markdown remains the authored identity input.

* Conventional `rules/*.mdc` documents. Present only when rules are
* discovered; optional so hand-constructed models predating rules remain valid.
*/
readonly rules?: readonly NormalizedRule[];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Canonicalize rule paths in project identity

For any project containing a rule, canonicalizeNormalizedModel() leaves the new rule's absolute source and provenance.sourcePath untouched because project-context.ts was not extended alongside this property. The same project copied to a different root therefore receives a different supposedly root-independent modelDigest, and rule paths also bypass modelPathReferences() containment checks; rules need the same canonical path handling as skills, scripts, and assets.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a516fa8. canonicalizeNormalizedModel now maps model.rules (provenance + source through canonicalCompilerPath), and rule paths joined modelPathReferences so the escaping-path assertion covers them. Added the digest-stability regression in api.test.ts: two identical fixtures (one target-restricted rule, one shared rule) in different temp roots produce equal modelDigests, rule sources appear in sourceInputs, and a body edit changes the digest so the test cannot pass vacuously. rules/*.mdc was already covered by the generic project source snapshot.

...(nativeHooks.length === 0 ? {} : { nativeHooks }),
...(packageBuild === undefined ? {} : { packageBuild }),
...(payloads.length === 0 ? {} : { payloads }),
...(rules.length === 0 ? {} : { rules }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include rules in inspection skip accounting

When an untargeted rule inherits a selected host without rule support, such as portable or claude, omission by that host's planner is intentional, but inspectableComponents() in api.ts never includes model.rules and InspectionSkippedComponent.kind has no rule variant. As a result inspect() reports neither an artifact entry nor the expected unsupported-capability skipped item, making the inspection incomplete precisely for the defaulted-target flow introduced here.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a516fa8. InspectionSkippedComponent.kind gains 'rule' and inspectableComponents now includes model.rules with the rules capability, so untargeted rules on claude/codex/portable report unsupported-capability and authored restrictions report excluded-by-targets. The inspect test now runs all four targets and asserts cursor reports no rule skip while the other three report both reasons.

…ows (#100 stage 2)

Conventional rules/*.mdc parse against a closed frontmatter schema
(description/globs/alwaysApply plus peeled targets; AB4900-AB4906),
normalize into the model, and lower byte-faithfully into the Cursor
plugin and the multi-host bundle's Cursor half with a manifest rules
pointer. Claude, Codex, and portable record rules as honestly
unavailable; the composite row stays the Claude-and-Codex intersection.
Capability evidence pins the official cursor/plugins schema's rules
component pointer.
…tted rules, canonicalize rule identity paths, count rules in inspection skips

Emitted rule documents rebuild frontmatter without the peeled targets
key (byte-identical when no targets were authored); rule source and
provenance paths canonicalize in the model digest with a two-root
stability regression; inspect skip accounting gains the rule kind so
per-host omissions surface with intersection-rule reasons.
@pkg-pr-new

pkg-pr-new Bot commented Sep 1, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@207
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@207
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@207

commit: a516fa8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant